// eee.Sheffield.PZ.Imaging
//
// Copyright ?Ping Zou, 2007
// sg71.cherub@gmail.com

namespace eee.Sheffield.PZ.Imaging
{
	using System;
	using System.Drawing;
	using System.Drawing.Imaging;
    using eee.Sheffield.PZ.Math;
	
	/// <summary>
	/// extract scanline methods
	/// </summary>
	public class ExtractScanline
	{
        #region Fields
        private PZPoint p1 = null;		// point 1
        private PZPoint p2 = null;		// point 2
        private PZDirection sd = null;	// scanline direction
        private PZMath_vector fg = null;	// scanline profile intensities
        private PZPoint[] fp = null;	// samples coordinate
        private int samplerate = 0;	// sample rate
        private int widthofscanline = 0;	// width of scanline
        private int length = 0;			// length = widthofscanline * samplerate

        /// <summary>
        /// 0 - by a point and a scanline direction
        /// 1 - by two points
        /// </summary>
        private int method = 0;	// extract method        
        #endregion

        #region Properties
        public PZMath_vector ScanlineProfile { get { return new PZMath_vector(fg); } }
		
        /// <summary>
        /// property p1
        /// </summary>
        public PZPoint P1 { set { p1 = value; } get { return p1; } }

        /// <summary>
        /// property p2
        /// </summary>
        public PZPoint P2 { set { p2 = value; } get { return p2; } }

        /// <summary>
        /// property sd
        /// </summary>
        public PZDirection ScanlineDirection { set { sd = value; } get { return sd; } }
        public PZMath_vector Fg { get { return fg; } }
        public PZPoint[] Fp { get { return fp; } } 
        #endregion

        /// <summary>
        /// set extracting method
        /// </summary>
        /// <param name="i">method index</param>
        public void SetMethod(int i)
        {
            if (i < 0 || i >= 2)
                PZMath_errno.ERROR("ExtractScanline::SetMethod(), valid method index.");
            method = i;
        } // SetMethod()


        ///// <summary>
        ///// access to element of fg
        ///// </summary>
        ///// <param name="i">index</param>
        ///// <returns></returns>
        //public double Fg(int i)
        //{
        //    if (i < 0 || i >= length)
        //        PZMath_errno.ERROR("ExtractScanline::Fg(), Index out of Range.");
        //    return fg[i];
        //} // Fg();

        ///// <summary>
        ///// access to element of fp
        ///// </summary>
        ///// <param name="i">index</param>
        ///// <returns></returns>
        //public PZPoint Fp(int i)
        //{
        //    if (i < 0 || i >= length)
        //        PZMath_errno.ERROR("ExtractScanline::Fp(), Index out of Range.");
        //    return fp[i];
        //} // Fp();
		
		/// <summary>
		/// empty constructor
		/// </summary>
		public ExtractScanline() 
		{
			p1 = new PZPoint();
			p2 = new PZPoint();
			sd = new PZDirection();
		} // ExtractScanline()

		/// <summary>
		/// constructor
		/// </summary>
		/// <param name="inputp">center point</param>
		/// <param name="inputsd">scanline direction</param>
		/// <param name="s">sample rate</param>
		/// <param name="w">width of scanline</param>
		public ExtractScanline(PZPoint inputp, PZDirection inputsd, int s, int w)
		{
			method = 0;
			p1 = inputp;
			p2 = new PZPoint();
			sd = inputsd;
			samplerate = s;
			widthofscanline = w;
			length = samplerate * widthofscanline;
            fp = new PZPoint[length];
			for (int i = 0; i < length; i ++)
				fp[i] = new PZPoint();
            fg = new PZMath_vector(length);
		} // ExtractScanline(PZPoint, PZDirection, int, int)

		public ExtractScanline(PZPoint inputp1, PZPoint inputp2, int s, int w)
		{
			method = 1;
			p1 = inputp1;
			p2 = inputp2;
			sd = new PZDirection();
			samplerate = s;
			widthofscanline = w;
			length = samplerate * widthofscanline;
			fp = new PZPoint[length];
			for (int i = 0; i < length; i ++)
				fp[i] = new PZPoint();
            fg = new PZMath_vector(length);
		} // ExtractScanline(PZPoint, PZpoint, int, int)

		/// <summary>
		/// extract scanline, save results in fg and fp
		/// </summary>
		/// <param name="srcImg"></param>
		/// <returns></returns>
		public Bitmap Apply(Bitmap srcImg)
		{			
			int width = srcImg.Width;
			int height = srcImg.Height;

			if (method == 0)
				// extract scanline by a point and a scanline direction
				ExtractScanlinePD(srcImg);
			if (method == 1)
				// extract scanline by 2 points
				ExtractScanline2P(srcImg);

			// -- return an useless dstImg
			// create new image
            Bitmap dstImg = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
            return dstImg;
		} // Apply()

		/// <summary>
		/// extract scanline by a point and a scanline direction
		/// </summary>
		/// <param name="srcImg"></param>
		private void ExtractScanlinePD(Bitmap srcImg)
		{
			int width = srcImg.Width;
			int height = srcImg.Height;

			// -- extract scanline
			int halfwidth = widthofscanline / 2;
			Interpolate interpolatefilter = new Interpolate();
			interpolatefilter.SetIterpolateMethod(2);	// use Cubic approximation
			for (int i = 0; i < length; i ++)
			{
				double t = (double) i / (double) samplerate;
				fp[i].x = p1.x + (t - halfwidth) * sd.x;
				fp[i].y = p1.y + (t - halfwidth) * sd.y;
				if (fp[i].x >= width || fp[i].x < 0
					|| fp[i].y >= height || fp[i].y < 0)
					fg[i] = 0.0;
				else
				{
					PZPoint interpolatepoint = new PZPoint(fp[i].x, fp[i].y);
					fp[i].x = fp[i].x;
					fp[i].y = fp[i].y;
					interpolatefilter.P = interpolatepoint;
					interpolatefilter.Apply(srcImg);
					fg[i] = interpolatefilter.I;
				} 
			}
		} // ExtractScanlinePD()

		/// <summary>
		/// extract scanline by 2 points
		/// </summary>
		/// <param name="srcImg"></param>
		private void ExtractScanline2P(Bitmap srcImg)
		{
			int width = srcImg.Width;
			int height = srcImg.Height;

			// -- calculate scanline direction
			sd.GetDirectionFrom2Points(p1, p2);
			// -- extract scanline
			Interpolate interpolatefilter = new Interpolate();
			interpolatefilter.SetIterpolateMethod(2);	// use Cubic approximation
			for (int i = 0; i < length; i ++)
			{
				double t = (double) i / (double) samplerate;
				fp[i].x = p1.x + t * sd.x;
				fp[i].y = p1.y + t * sd.y;
				if (fp[i].x >= width || fp[i].x < 0
					|| fp[i].y >= height || fp[i].y < 0)
					fg[i] = 0.0;
				else
				{
					PZPoint interpolatepoint = new PZPoint(fp[i].x, fp[i].y);
					fp[i].x = fp[i].x;
					fp[i].y = fp[i].y;
					interpolatefilter.P = interpolatepoint;
					interpolatefilter.Apply(srcImg);
					fg[i] = interpolatefilter.I;
				} 
			}
		} // ExtractScanline2P()

	} // ExtractScanline
}
